package cn.duyo.spring.context.event;

import cn.duyo.spring.beans.BeansException;
import cn.duyo.spring.beans.factory.BeanFactory;
import cn.duyo.spring.beans.factory.BeanFactoryAware;
import cn.duyo.spring.context.ApplicationEvent;
import cn.duyo.spring.context.ApplicationListener;
import cn.duyo.spring.util.ClassUtils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Set;

/**
 * @author du
 */
@SuppressWarnings({"unchecked", "rawtypes"})
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {

    public final Set<ApplicationListener<ApplicationEvent>> applicationListeners = new LinkedHashSet<>();

    private BeanFactory beanFactory;

    @Override
    public void addApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.add((ApplicationListener<ApplicationEvent>) listener);
    }

    @Override
    public void removeApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.remove(listener);
    }

    @Override
    public final void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event) {
        LinkedList<ApplicationListener> allListeners = new LinkedList<ApplicationListener>();
        for (ApplicationListener<ApplicationEvent> listener : applicationListeners) {
            /**
             * TODO: 寻找 implements ApplicationListener<CustomEvent> 实现接口的泛型参数(实现的接口可能多个，泛型参数也可能多个)
             *  找到其中事件类型 CustomEvent，查看订阅者(监听器)的事件类型是否是 触发事件event的同类型或者父类。是的话就允许循环触发符合条件的监听器的 onApplicationEvent 方法
             */
            if (supportsEvent(listener, event)) allListeners.add(listener);
        }
        return allListeners;
    }

    /**
     * 监听器是否对该事件感兴趣
     */
    protected boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener, ApplicationEvent event) {
        Class<? extends ApplicationListener> listenerClass = applicationListener.getClass();

        // 按照 CglibSubclassingInstantiationStrategy、SimpleInstantiationStrategy 不同的实例化类型，需要判断后获取目标 class
        Class<?> targetClass = ClassUtils.isCglibProxyClass(listenerClass) ? listenerClass.getSuperclass() : listenerClass;
        // 用于获取一个类直接实现的接口的类型信息‌。该方法返回一个Type数组，表示该类直接实现的接口类型(携带泛型)。如果该类没有实现任何接口，则返回一个空数组‌
        Type genericInterface = targetClass.getGenericInterfaces()[0];

        // 获取接口的第一个泛型参数
        Type actualTypeArgument = ((ParameterizedType) genericInterface).getActualTypeArguments()[0];
        String className = actualTypeArgument.getTypeName();
        Class<?> eventClassName;
        try {
            eventClassName = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new BeansException("wrong event class name: " + className);
        }
        // 判定此 eventClassName 对象所表示的类或接口与指定的 event.getClass() 参数所表示的类或接口是否相同，或是否是其超类或超接口。
        // isAssignableFrom是用来判断子类和父类的关系的，或者接口的实现类和接口的关系的，默认所有的类的终极父类都是Object。如果A.isAssignableFrom(B)结果是true，证明B可以转换成为A,也就是A可以由B转换而来。
        /**
         * A.isAssignableFrom(B) 的语义是判断B是否为A的子类或实现类 (A父类, B子类)
         */
        return eventClassName.isAssignableFrom(event.getClass());
    }

}